#include "Socket.hpp"
#include "Epoller.hpp"

class EpollServer
{
public:
    EpollServer(uint16_t port) : _port(port)
    {
        _epoll = new Epoller();
        _sock = new Sock();
    }

    void Init()
    {
        _sock->Socket();
        _sock->Bind(_port);
        _sock->Listen();

        lg(Info, "create listen socket success: %d\n", _sock->GetListenSock());

        _epoll->EpollUpdate(EPOLL_CTL_ADD, _sock->GetListenSock(), EPOLLIN);
    }

    void Start()
    {
        for (;;)
        {
            int n = _epoll->EpollWait(events, sizeof(events));
            switch (n)
            {
            case -1:
                lg(Error, "select error: code:%d msg:%s", errno, strerror(errno));
                exit(-1);
                break;
            case 0:
                lg(Info, "time out ...");
                //std::cout << "超时，进行下一次等待" << std::endl;
                break;
            default:
                lg(Debug, "event happened, fd:%d", events[0].data.fd);
                //std::cout << "有" << n << "个文件描述符处于就绪状态" << std::endl;
                Dispatcher(n);
                break;
            }
        }
    }

    void Dispatcher(int n)
    {
        for(int i = 0; i < n; ++i)
        {
            // if(events[i].data.fd == _sock->GetListenSock()){
            //     Accepter();
            // }
            // else{
            //     Recver(events[i].data.fd);
            // }

            if(events[i].events & EPOLLIN)
            {
                if(events[i].data.fd == _sock->GetListenSock())
                    Accepter();
                else
                    Recver(events[i].data.fd);
            }
            else if(events[i].events & EPOLLOUT){

            }
            else{

            }
        }
    }

    void Accepter() // 链接管理器
    {
        std::string clientip;
        uint16_t clientport;
        int sock = _sock->Accept(clientip, clientport);
        if (sock < 0) return;
            lg(Info, "accept success, %s: %d, sock fd: %d", clientip.c_str(), clientport, sock);

        _epoll->EpollUpdate(EPOLL_CTL_ADD, sock, EPOLLIN);

        lg(Info, "get a new link, client info@ %s:%d", clientip.c_str(), clientport);
    }


    void Recver(int fd)
    {
        char buffer[128];
        std::string res = "get mseeage, fd: ";
        res += std::to_string(fd);
        res += " msg: ";

        int n = recv(fd, buffer, sizeof(buffer) - 1, 0);

        if (n < 0)
        {
            lg(Error, "recv error, fd:%d, code:%d, msg:%s", fd, errno, strerror(errno));
            _epoll->EpollUpdate(EPOLL_CTL_DEL, fd, 0);
            close(fd);
            return;
        }
        else if (0 == n)
        {
            // 对方写端关闭
            lg(Warning, "close file, fd:%d", fd);
            _epoll->EpollUpdate(EPOLL_CTL_DEL, fd, 0);
            close(fd);;
            return;
        }
        else
        {
            buffer[n] = 0;
            res += buffer;
        }

        std::cout << res << std::endl;
    }


    

private:
    Epoller *_epoll = nullptr;
    Sock *_sock = nullptr;
    uint16_t _port;

    struct epoll_event events[64];
};
